<!DOCTYPE html>
<html>
<head>
    <title>WebRTC</title>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
    <script src="js/jquery-1.8.0.min.js"></script>
    <script src="js/adapter.js"></script>
    <style>
        #log {
            width: 100%;
            height: 200px;
            border: solid 1px;
            overflow-y: scroll;
        }

        input[type='button'] {
            width: 300px;
            height: 50px;
        }
    </style>
</head>
<body>
<div style="margin: 20px auto;">
    <input id="start" onclick="onClickStart()" type="button" value="Start"/>
    <input id="guest" onclick="onClickGuest()" type="button" value="Guest"/>
</div>
<div style="width: 900px;height: 450px;text-align: center;margin: 20px auto;">
    <div style="width: 400px;height: 430px;float: left;background: #EEEEEE;">
        localVideo
        <video autoplay id="localVideo" style="width: 400px;height: 400px;"></video>
    </div>
    <div style="width: 400px;height: 430px;float: left;background: #EEEEEE;margin-left: 20px;">
        remoteVideo
        <video autoplay id="remoteVideo" style="width: 400px;height: 400px;float: left;"></video>
    </div>
</div>
<div id="log" style="margin: 20px auto;">
    <ul></ul>
</div>
<script type="text/javascript">
    var url = "";
    if (window.location.protocol === 'http:') {
        url = 'ws://' + window.location.host + '/websocket';
    } else {
        url = 'wss://' + window.location.host + '/websocket';
    }

    var signalingChannel = new WebSocket(url);
    var configuration = {
        // 'iceServers': [{
        //     'url': 'stun:stun.l.google.com:19302'
        //     // 'url': 'stun:stun.freeswitch.org'
        // }]
        'iceServers': [
            {"url": "stun:47.110.14.77:3478"},
            {"url": "stun:stun.freeswitch.org"},
            {"url": "stun:stun.xten.com"},
            {"url": "stun:stun.ekiga.net"}
        ]
    };
    var pc;
    var localVideo;
    var remoteVideo;

    function log(msg) {
        $("#log").find("ul").prepend("<li>" + new Date().Format("yyyy-MM-dd hh:mm:ss") + "=" + msg + "</li>");
    }

    function onClickStart() {
        start();
        signalingChannel.send(JSON.stringify({
            'makehost': '1'
        }));
    }

    var bGuest = false;

    function onClickGuest() {
        bGuest = true;
        signalingChannel.send(JSON.stringify({
            'makeguest': '1'
        }));
    }

    // call start() to initiate
    function start() {
        pc = new RTCPeerConnection(configuration);
        localVideo = $("#localVideo")[0];
        remoteVideo = $("#remoteVideo")[0];

        // send any ice candidates to the other peer
        pc.onicecandidate = function (evt) {
            if (evt.candidate) {
                signalingChannel.send(JSON.stringify({
                    'candidate': evt.candidate
                }));
                log("send candidate." + evt.candidate);
            }
        };

        // let the 'negotiationneeded' event trigger offer generation
        pc.onnegotiationneeded = function () {
            //if(!bGuest){
            log("creating Offer.");
            pc.createOffer(localDescCreated, logError);
            //}
        };

        // once remote stream arrives, show it in the remote video element
        pc.onaddstream = function (evt) {
            log("receiving remote video.");
            remoteVideo.src = URL.createObjectURL(evt.stream);
        };

        // get a local stream, show it in a self-view and add it to be sent
        navigator.getUserMedia({
            'audio': true,
            'video': true
        }, function (stream) {
            log("starting local video.");
            localVideo.src = URL.createObjectURL(stream);
            pc.addStream(stream);
        }, logError);
    }

    function localDescCreated(desc) {
        pc.setLocalDescription(desc, function () {
            log("got local sdp.");
            signalingChannel.send(JSON.stringify({
                'sdp': pc.localDescription
            }));
        }, logError);
    }

    signalingChannel.onclose = function (event) {
        log("WS Closed=" + event)
    };

    signalingChannel.onerror = function (event) {
        log("WS ERROR=" + event)
    };

    signalingChannel.onopen = function (event) {
        log("Connection established! " + event)
    };

    signalingChannel.onmessage = function (evt) {
        var message = null;
        try {
            message = JSON.parse(evt.data);
        } catch (err) {
            //alert("Json Parse Error By OnMessage!");
        }
        if (message === null) {
            if (evt && evt.data)
                log("response=" + evt.data);
            return;
        }

        if (!pc && (message.sdp || message.candidate))
            start();

        if (message.sdp) {
            log("getting remote sdp=");
            var remoteSDP = JSON.parse(message.sdp);
            log("getting remote sdp OBJECT=" + remoteSDP);
            pc.setRemoteDescription(new RTCSessionDescription(remoteSDP), function () {
                log("got remote sdp.");
                // if we received an offer, we need to answer
                if (pc.remoteDescription.type === 'offer') {
                    log("creating Answer.");
                    pc.createAnswer(localDescCreated, logError2);
                }
            }, logError2);
        } else if (message.candidate) {
            log("receiving candidate");
            var remoteCandidate = JSON.parse(message.candidate);
            pc.addIceCandidate(new RTCIceCandidate(remoteCandidate));
        } else {
            log("msg=" + message);
        }
    };

    function logError(error) {
        log(error.name + ': ' + error.message);
    }

    function logError2(error) {
        log(error);
    }


    // 对Date的扩展，将 Date 转化为指定格式的String
    // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符，
    // 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
    // 例子：
    // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
    // (new Date()).Format("yyyy-M-d h:m:s.S")   ==> 2006-7-2 8:9:4.18
    Date.prototype.Format = function (format) {
        var o = {
            "M+": this.getMonth() + 1, //month
            "d+": this.getDate(),    //day
            "h+": this.getHours(),   //hour
            "m+": this.getMinutes(), //minute
            "s+": this.getSeconds(), //second
            "q+": Math.floor((this.getMonth() + 3) / 3),  //quarter
            "S": this.getMilliseconds() //millisecond
        };
        if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(format))
                format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
        return format;
    }
</script>
</body>
</html>